/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package labox.innovation.db.core;

import java.sql.Connection;
import java.sql.SQLException;

import labox.innovation.config.Config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;

public class L2DatabaseFactory {
	public static boolean AUTOCOMMITONCLOSE;

	public static int INITIALPOOLSIZE;

	static Logger _log = LoggerFactory.getLogger(L2DatabaseFactory.class.getName());

	public static enum ProviderType {
		MySql, MsSql
	}

	// =========================================================
	// Data Field
	private static final L2DatabaseFactory _instance = new L2DatabaseFactory();

	private ProviderType _providerType;

	private MysqlConnectionPoolDataSource _source;

	// private static final MiniConnectionPoolManager poolMgr;

	// =================================== ======================
	// Constructor
	public L2DatabaseFactory() {
		try {
			if (Config.DATABASE_MAX_CONNECTIONS < 2) {
				Config.DATABASE_MAX_CONNECTIONS = 2;
				_log.warn("A minimum of " + Config.DATABASE_MAX_CONNECTIONS + " db connections are required.", Config.SERVER_ID, "db��������");
			}

			_source = new MysqlConnectionPoolDataSource();

			_source.setDatabaseName(Config.DATABASE_DRIVER);
			_source.setURL(Config.DATABASE_URL);
			_source.setUser(Config.DATABASE_LOGIN);
			_source.setPassword(Config.DATABASE_PASSWORD);
			/* Test the connection */
			_source.getConnection().close();
			MiniConnectionPoolManager.getMiniConnectionPoolManager(_source, Math.max(4, Config.DATABASE_MAX_CONNECTIONS));
			if (_log.isDebugEnabled())
				_log.debug("Database Connection Working");

			if (Config.DATABASE_DRIVER.toLowerCase().contains("microsoft"))
				_providerType = ProviderType.MsSql;
			else
				_providerType = ProviderType.MySql;
		} catch (SQLException x) {
			x.printStackTrace();
			if (_log.isDebugEnabled())
				_log.debug("Database Connection FAILED");
		} catch (Exception e) {
			e.printStackTrace();
			if (_log.isDebugEnabled())
				_log.debug("Database Connection FAILED");
		}
	}

	// =========================================================
	// Method - Public
	public final String prepQuerySelect(String[] fields, String tableName, String whereClause, boolean returnOnlyTopRecord) {
		String msSqlTop1 = "";
		String mySqlTop1 = "";
		if (returnOnlyTopRecord) {
			if (getProviderType() == ProviderType.MsSql)
				msSqlTop1 = " Top 1 ";
			if (getProviderType() == ProviderType.MySql)
				mySqlTop1 = " Limit 1 ";
		}
		String query = "SELECT " + msSqlTop1 + safetyString(fields) + " FROM " + tableName + " WHERE " + whereClause + mySqlTop1;
		return query;
	}

	public void shutdown() {
		try {
			// _source.close();
			MiniConnectionPoolManager.dispose();
		} catch (Exception e) {
			_log.info("MiniConnectionPoolManager shutdown error", Config.SERVER_ID, e.getMessage());
		}
		_source = null;
	}

	public final String safetyString(String... whatToCheck) {
		// NOTE: Use brace as a safty precaution just incase name is a reserved
		// word
		final char braceLeft;
		final char braceRight;

		if (getProviderType() == ProviderType.MsSql) {
			braceLeft = '[';
			braceRight = ']';
		} else {
			braceLeft = '`';
			braceRight = '`';
		}

		int length = 0;

		for (String word : whatToCheck) {
			length += word.length() + 4;
		}

		final StringBuilder sbResult = new StringBuilder(length);

		for (String word : whatToCheck) {
			if (sbResult.length() > 0) {
				sbResult.append(", ");
			}
			sbResult.append(braceLeft);
			sbResult.append(word);
			sbResult.append(braceRight);
		}

		return sbResult.toString();
	}

	// Property - Public
	public static L2DatabaseFactory getInstance() throws SQLException {
		return _instance;
	}

	public Connection getConnection() throws SQLException{
		Connection con = null;
		while (con == null) {
			try {
				con = MiniConnectionPoolManager.getConnection();
			} catch (SQLException e) {
				_log.warn("L2DatabaseFactory:Connection() failed, trying again ", Config.SERVER_ID,e.getMessage());
				throw e;
			}
		}
		return con;
	}

	public final ProviderType getProviderType() {
		return _providerType;
	}
}
